package starfield;

import starfield.ui.MainFrame;
import starfield.ui.PreferencesFrame;
import starfield.modpack.web.SyncingException;
import starfield.modpack.Modpack;
import starfield.modpack.web.WebModpack;
import starfield.util.JSONUtils;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.commons.io.FileUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

public class Application {
    public static final String VERSION = "Alpha 0.1";
    public static final String TTL_INSTALL_PATH = "Install path";
    public static final String TTL_INSTALL_PATH_GUESS = "Install path guessing";
    public static final String MSG_INVALID_INSTALL_PATH = "Specified path is an invalid Starbound install path.";
    public static final String MSG_INSTALL_PATH_GUESS_FAIL = "Could not guess Starbound install path.";
	
	public static final String COMPILE_DESTINATION = "mods" + File.separator + "starfield";
	public static final String TEMP_COMPILATION_DIRECTORY_NAME = "temp";
	public static final String VANILLA_ASSETS_FOLDER = "assets";
	
	private static ArrayList<Modpack> modpacks;
	private static MainFrame mainFrame;
	
    public static void main(String[] args) {
		try {
			initializeLookAndFeel();

			if (Configuration.load() && Configuration.isValid()) {
				MainFrame.launch();
			} else {
				PreferencesFrame.launch(true);
			}
		} catch (Exception ex) {
			JOptionPane.showMessageDialog(null, "Fatal error: " +  System.lineSeparator() + ex.getMessage(), "Starfield", JOptionPane.ERROR_MESSAGE);
		}
    }
	
	public static MainFrame getMainFrame() {
		return mainFrame;
	}
	
	public static void setMainFrame(MainFrame mainFrame) {
		Application.mainFrame = mainFrame;
	}
	
	public static ArrayList<Modpack> getModpacks() {
		return modpacks;
	}
	
	public static Modpack findModpack(String directoryName) {
		for (Modpack modpack : getModpacks()) {
			if (modpack.getName().equals(directoryName)) {
				return modpack;
			}
		}
		
		return null;
	}
	
	public static void loadModpacks() throws IOException, ParsingException {
		modpacks = new ArrayList<>();
		loadLocalModpacks(loadWebModpacks());
	}
	
	private static ArrayList<String> loadWebModpacks() throws IOException, ParsingException {
		ArrayList<String> failed = new ArrayList<>();
		
		File wmlFile = new File(WebModpack.getListFilePath());
		
		if (!wmlFile.exists() || !wmlFile.isFile()) {
			JSONObject emptyObject = new JSONObject();
			
			try {
				FileUtils.writeStringToFile(wmlFile, emptyObject.toJSONString());
			} catch (IOException ex) {
				throw new IOException("Could not find the web modpacks list file, and could not create it.");
			}
		}
		
		Object parsedJson = JSONValue.parse(FileUtils.readFileToString(wmlFile));

		if (parsedJson instanceof JSONObject) {
			JSONObject webModpackListJson = (JSONObject)parsedJson;

			Iterator<?> keys = webModpackListJson.keySet().iterator();

			while (keys.hasNext()) {
				String webModpackDirectoryName = (String)keys.next();
				
				File modpackDirectory = new File(Modpack.getDirectoryPath(webModpackDirectoryName));
				
				if (!modpackDirectory.exists() || !modpackDirectory.isDirectory()) {
					if (!modpackDirectory.mkdirs()) {
						JOptionPane.showMessageDialog(
							null, 
							"Failed to find web modpack directory '" + webModpackDirectoryName + "', and failed to create it.",
							"Starfield", 
							JOptionPane.WARNING_MESSAGE);
					
						continue;
					}
				}
				
				try {
					JSONObject webModpackJson = JSONUtils.getObject(webModpackListJson, webModpackDirectoryName);
					WebModpack.load(webModpackDirectoryName, webModpackJson, false);
				} catch (IOException | ParsingException | SyncingException ex) {
					JOptionPane.showMessageDialog(
						null, 
						"Could not load web modpack '" + webModpackDirectoryName + "': " +
						System.lineSeparator() + System.lineSeparator() + 
						ex.getMessage(), 
						"Starfield", 
						JOptionPane.WARNING_MESSAGE);

					failed.add(webModpackDirectoryName);
				}
			}
		} else {
			throw new ParsingException("Root of JSON must be an object.");
		}
		
		return failed;
	}
	
	public static void saveWebModpacksList() throws IOException {
		File wmlFile = new File(WebModpack.getListFilePath());

		JSONObject wmlJson = new JSONObject();

		for (Modpack modpack : modpacks) {
			if (modpack instanceof WebModpack) {
				WebModpack webModpack = (WebModpack)modpack;
				
				JSONObject webModpackJson = webModpack.serializeConnection();
				
				wmlJson.put(webModpack.getName(), webModpackJson);
			}
		}
		
		FileUtils.writeStringToFile(wmlFile, wmlJson.toJSONString());
	}
	
	private static void loadLocalModpacks(ArrayList<String> ignored) throws IOException {
		File modpacksDirectory = new File(Modpack.getModpacksDirectoryPath());
		
		if (!modpacksDirectory.exists() || !modpacksDirectory.isDirectory()) {
			if (!modpacksDirectory.mkdirs()) {
				throw new IOException("Could not find modpacks directory, and could not create it.");
			}
		}
		
		String[] modpackDirectoryNames = modpacksDirectory.list();

		for (String modpackDirectoryName : modpackDirectoryNames)
		{
			if (!ignored.contains(modpackDirectoryName) && Application.findModpack(modpackDirectoryName) == null) {
				File modpackDirectory = new File(modpacksDirectory.getAbsolutePath() + File.separator + modpackDirectoryName);

				if (modpackDirectory.isDirectory())
				{
					try {
						Modpack modpack = Modpack.load(modpackDirectoryName);
					} catch (IOException | ParsingException ex) {
						JOptionPane.showMessageDialog(
							null, 
							"Could not load modpack '" + modpackDirectoryName + "': " +
							System.lineSeparator() + System.lineSeparator() + 
							ex.getMessage(), 
							"Starfield", 
							JOptionPane.WARNING_MESSAGE);
					}
				}
			}
		}
	}
	
	private static void initializeLookAndFeel() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());        
		} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
			
		if (System.getProperty("os.name").contains("Windows")) {
			UIManager.getDefaults().put("TabbedPane.contentBorderInsets", new Insets(-3,0,0,2));
		}
	}
}
